#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   OBU_Message_test.py
@Time    :   2025/04/17 13:31:28
@Author  :   YangLiang 
@Version :   1.0
@Contact :   yangl@genvict.com
@License :   (C)Copyright 2022-2025
@Desc    :   OBU 信息测试
'''

from pytest_assume.plugin import assume
import pytest
import logging
import time
import allure
import sys
import random
sys.dont_write_bytecode = True
import Set_up
from aes_cmac import AESCMAC

class Test_OBU_message:
    '''
    OBU信息测试
    '''

    @allure.severity('normal')
    @allure.title('检查OBU 软件版本')
    @allure.description('检查OBU 软件版本')
    def test_OBU_Software_Version(self, action, Driver):
        iStep = 1
        # 读取OBU软件版本
        iStep, VersionData = Driver['CAN'].getOBUSoftwareVersion(Driver, iStep)
        start_marker = '1E 8C 02 04 00'
        start_index = VersionData.find(start_marker)
        if start_index != -1:
            # 截取从标记开始到结尾的数据(去掉最后一个字节)
            version_hex = VersionData[start_index + len(start_marker):-8].strip()
            # 转换为ASCII字符串
            version_str = bytes.fromhex(version_hex.replace(" ", "")).decode('ascii').replace(" ", "")
            logging.info(f"获取到的OBU软件版本: {version_str}")
        with allure.step(f'第{iStep}步:判断OBU软件版本 # 软件版本应该是{Set_up.OBU_Software_Version}'):
            with assume: assert version_str == Set_up.OBU_Software_Version, logging.error(f'OBU软件版本应该是{Set_up.OBU_Software_Version},实际为：{version_str}')
    
    # @allure.severity('normal')
    # @allure.title('5.8G软件升级功能检测')
    # @allure.description('5.8G软件升级功能检测')
    # def test_OBU_Software_Upgrade(self, action, Driver):
    #     iStep = 1
    #     # 读取OBU软件版本
    #     iStep, version, updateStatus = Driver['CAN'].upgrade_OBU(Driver, iStep)
    #     with allure.step(f'第{iStep}步:判断OBU软件升级是否成功 # 成功'):
    #         with assume: assert updateStatus == True, logging.error(f'OBU软件升级失败')
    #     with allure.step(f'第{iStep}步:判断OBU软件版本是否正确 # 软件版本应该是{Set_up.OBU_Software_Version}'):
    #         with assume: assert version == Set_up.OBU_Software_Version, logging.error(f'OBU软件版本应该是{Set_up.OBU_Software_Version},实际为：{version}')
    

    @allure.severity('normal')
    @allure.title('5.8G检查OBU蓝牙名称')
    @allure.description('5.8G检查OBU蓝牙名称')
    def test_OBU_BleName(self, action, Driver):
        iStep = 1
        bleName = "ETC-JY-8888"
        # 写蓝牙名称
        iStep, SetBleName = Driver['CAN'].setOBUBleName(Driver, iStep, bleName)
        # 断电重启
        iStep= Driver['CAN'].restartETC_Power(Driver, iStep)
        # 读取OBU蓝牙名称
        iStep, BleName = Driver['CAN'].getOBUBleName(Driver, iStep)
        start_marker = '1E 88 02 00 00'
        start_index = BleName.find(start_marker)
        if start_index != -1:
            # 截取从标记开始到结尾的数据(去掉最后一个字节)
            BleName_hex = BleName[start_index + len(start_marker):-8].strip()
            # 转换为ASCII字符串
            BleName_str = bytes.fromhex(BleName_hex.replace(" ", "")).decode('ascii')
            logging.info(f"获取到的OBU蓝牙名称: {BleName_str}")
        with allure.step(f'第{iStep}步:判断OBU蓝牙名称 # 蓝牙名称应该是{bleName}'):
            with assume: assert BleName_str == bleName, logging.error(f'OBU蓝牙名称应该是{bleName},实际为：{BleName_str}')

    @allure.severity('normal')
    @allure.title('5.8G检查OBU ID与SN')
    @allure.description('5.8G检查OBU ID与SN')
    def test_OBU_ID_SN_58G(self, action, Driver):
        iStep = 1
        OBU_ID = "99999999"
        OBU_SN = "8888888888888888"
        # 写入ID SN
        iStep = Driver['CAN'].setOBU_ID_SN(Driver, iStep, OBU_ID, OBU_SN)
        # 断电重启
        iStep= Driver['CAN'].restartETC_Power(Driver, iStep)

        # 读取OBU ID与SN
        iStep, ID_SN = Driver['CAN'].getOBU_ID_SN(Driver, iStep)
        start_marker = '1E 81 02 00 00'
        start_index = ID_SN.find(start_marker)
        if start_index != -1:
            # 截取从标记开始到结尾的数据(去掉最后一个字节)
            ID_SN_hex = ID_SN[start_index + len(start_marker):-8].strip().replace(" ", "")
            ID = ID_SN_hex[0:8]
            # 转换为ASCII字符串
            SN = bytes.fromhex(ID_SN_hex[8:]).decode('ascii')
            logging.info(f"获取到的OBU ID与SN:{ID} {SN}")
        with allure.step(f'第{iStep}步:判断OBU ID # OBU ID应该是{OBU_ID}'):
            with assume: assert ID == OBU_ID, logging.error(f'OBU ID应该是{OBU_ID},实际为：{ID}')
        with allure.step(f'第{iStep}步:判断OBU SN # OBU SN应该是{OBU_SN}'):
            with assume: assert SN == OBU_SN, logging.error(f'OBU SN应该是{OBU_SN},实际为：{SN}')

    
    @allure.severity('normal')
    @allure.title('CAN检查OBU ID与SN')
    @allure.description('CAN检查OBU ID与SN')
    def test_OBU_ID_SN(self, action, Driver):
        iStep = 1
        OBU_ID = "88888888"
        OBU_SN = random.randint(0, 9999999999999999)
        OBU_SN = format(OBU_SN, '016d')
        # 写入ID SN
        iStep = Driver['CAN'].setOBU_ID_SN(Driver, iStep, OBU_ID, OBU_SN)
        time.sleep(1)
        # 读取OBU ID与SN
        iStep, SN = Driver['CAN'].getOBU_SN(Driver, iStep)
        with allure.step(f'第{iStep}步:判断OBU SN # OBU SN应该是{OBU_SN}'):
            with assume: assert SN == OBU_SN, logging.error(f'OBU SN应该是{OBU_SN},实际为：{SN}')



    @allure.severity('normal')
    @allure.title('检查OBU通行状态-通行正常')
    @allure.description('检查OBU通行状态-通行正常')
    def test_OBU_Tradeinfo_SystemSt_OK(self, action, Driver):
        iStep = 1
        iMoney = 0
        # 设置OBU交易状态
        iStep, TradeStatus = Driver['CAN'].SetOBUTradeMoney(Driver, iStep, iMoney, 2, 0)
        time.sleep(0.5)
        # 读取OBU交易状态
        iStep, ETC_TradeStatus = Driver['CAN'].getETC_TradeStatus(iStep)
        
        with allure.step(f'第{iStep}步:判断OBU交易状态 # 交易状态应该是0-通行正常'):
            with assume: assert ETC_TradeStatus == 0, logging.error(f'OBU交易状态应该是0,实际为: {ETC_TradeStatus:2x}')

    @allure.severity('normal')
    @allure.title('检查OBU通行状态-通行异常')
    @allure.description('检查OBU通行状态-通行异常')
    def test_OBU_Tradeinfo_SystemSt_NOK_01(self, action, Driver):
        iStep = 1
        iMoney = 0
        # 设置OBU交易状态
        iStep, TradeStatus = Driver['CAN'].SetOBUTradeMoney(Driver, iStep, iMoney, 2, 1)
        time.sleep(0.5)
        # 读取OBU交易状态
        iStep, ETC_TradeStatus = Driver['CAN'].getETC_TradeStatus(iStep)
        
        with allure.step(f'第{iStep}步:判断OBU交易状态 # 交易状态应该是1-通行异常'):
            with assume: assert ETC_TradeStatus == 1, logging.error(f'OBU交易状态应该是1,实际为: {ETC_TradeStatus:2x}')

    @allure.severity('normal')
    @allure.title('检查OBU通行状态-联系运营商')
    @allure.description('检查OBU通行状态-联系运营商')
    def test_OBU_Tradeinfo_SystemSt_NOK_02(self, action, Driver):
        iStep = 1
        iMoney = 0
        # 设置OBU交易状态
        iStep, TradeStatus = Driver['CAN'].SetOBUTradeMoney(Driver, iStep, iMoney, 2, 2)
        time.sleep(0.5)
        # 读取OBU交易状态
        iStep, ETC_TradeStatus = Driver['CAN'].getETC_TradeStatus(iStep)
        
        with allure.step(f'第{iStep}步:判断OBU交易状态 # 交易状态应该是2-联系运营商'):
            with assume: assert ETC_TradeStatus == 2, logging.error(f'OBU交易状态应该是2,实际为: {ETC_TradeStatus:2x}')

    @allure.severity('normal')
    @allure.title('检查OBU交易状态-无卡')
    @allure.description('检查OBU交易状态-无卡')
    def test_OBU_Tradeinfo_SystemSt_NOK_03(self, action, Driver):
        iStep = 1
        iMoney = 0
        # 设置OBU交易状态
        iStep, TradeStatus = Driver['CAN'].SetOBUTradeMoney(Driver, iStep, iMoney, 2, 3)
        time.sleep(0.5)
        # 读取OBU交易状态
        iStep, ETC_TradeStatus = Driver['CAN'].getETC_TradeStatus(iStep)
        
        with allure.step(f'第{iStep}步:判断OBU交易状态 # 交易状态应该是3-无卡'):
            with assume: assert ETC_TradeStatus == 3, logging.error(f'OBU交易状态应该是3,实际为: {ETC_TradeStatus:2x}')

    @allure.severity('normal')
    @allure.title('检查OBU交易金额')
    @allure.description('检查OBU交易金额')
    @pytest.mark.repeat(10)
    def test_OBU_Tradeinfo_Amount(self, action, Driver):
        iStep = 1
        for i in range(10):
            iMoney = random.randint(0, 1000)
            Entrance_Exit_Status = random.randint(1, 6)
            # 设置OBU交易金额
            iStep, TradeStatus = Driver['CAN'].SetOBUTradeMoney(Driver, iStep, iMoney, Entrance_Exit_Status)
            time.sleep(0.5)
            #
            with allure.step(f'第{iStep}步:判断OBU交易状态 # 交易成功'):
                with assume: assert TradeStatus == True, logging.error(f'OBU交易状态应该是True,实际为: {TradeStatus}')
            # 读取OBU CAN交易金额
            iStep, ETC_TransactionAmnt = Driver['CAN'].getETC_TradeAmount(iStep)
            with allure.step(f'第{iStep}步:判断OBU交易金额 # 交易金额应该是{iMoney}'):
                with assume: assert (ETC_TransactionAmnt - iMoney) < 0.01, logging.error(f'OBU交易金额应该是{iMoney},实际为: {ETC_TransactionAmnt}')
            # 读取OBU CAN出入口状态
            iStep, ETC_TradeEntranceStatus = Driver['CAN'].getETC_TradeEntranceStatus(iStep)
            with allure.step(f'第{iStep}步:判断OBU出入口状态 # 出入口状态应该是{Entrance_Exit_Status}'):
                with assume: assert ETC_TradeEntranceStatus == Entrance_Exit_Status, logging.error(f'OBU出入口状态应该是{Entrance_Exit_Status},实际为: {ETC_TradeEntranceStatus}')

    @allure.severity('normal')
    @allure.title('检查OBU入口状态')
    @allure.description('检查OBU入口状态')
    def test_OBU_EntranceStatus(self, action, Driver):
        iStep = 1
        # 设置出入口状态
        EntranceStatus = random.choice([1, 3, 5])
        iStep, _ = Driver['CAN'].SetOBUTradeMoney(Driver, iStep, 0, EntranceStatus)
        time.sleep(0.5)
        # 读取OBU出入口状态
        iStep, ETC_TradeEntranceStatus = Driver['CAN'].getETC_TradeEntranceStatus(iStep)
        time.sleep(0.5)
        with allure.step(f'第{iStep}步:判断OBU出入口状态 # 出入口状态应该是{EntranceStatus}'):
            with assume: assert ETC_TradeEntranceStatus == EntranceStatus, logging.error(f'OBU出入口状态应该是{EntranceStatus},实际为: {ETC_TradeEntranceStatus}')
    
    @allure.severity('normal')
    @allure.title('检查OBU出口状态')
    @allure.description('检查OBU出口状态')
    def test_OBU_ExitStatus(self, action, Driver):
        iStep = 1
        # 设置出入口状态
        ExitStatus = random.choice([2, 4, 6])
        iStep, _ = Driver['CAN'].SetOBUTradeMoney(Driver, iStep, 0, ExitStatus)
        time.sleep(0.5)
        # 读取OBU出入口状态
        iStep, ETC_TradeEntranceStatus = Driver['CAN'].getETC_TradeEntranceStatus(iStep)
        time.sleep(0.5)
        with allure.step(f'第{iStep}步:判断OBU出入口状态 # 出入口状态应该是{ExitStatus}'):
            with assume: assert ETC_TradeEntranceStatus == ExitStatus, logging.error(f'OBU出入口状态应该是{ExitStatus},实际为: {ETC_TradeEntranceStatus}')
    
    @allure.severity('normal')
    @allure.title('检查OBU出入口状态切换')
    @allure.description('检查OBU出入口状态切换')
    def test_OBU_Entrance_Exit_Status(self, action, Driver):
        iStep = 1
        enterStatus = [1, 3, 5]
        exitStatus = [2, 4, 6]
        for i in range(3):
            logging.info(f'OBU 切换到入口状态'.center(50, '-'))
            # 设置入口状态
            iStep, _ = Driver['CAN'].SetOBUTradeMoney(Driver, iStep, 0, enterStatus[i])
            time.sleep(0.5)
            # 读取OBU出入口状态
            iStep, ETC_TradeEntranceStatus = Driver['CAN'].getETC_TradeEntranceStatus(iStep)
            with allure.step(f'第{iStep}步:判断OBU出入口状态 # 出入口状态应该是{enterStatus[i]}'):
                with assume: assert ETC_TradeEntranceStatus == enterStatus[i], logging.error(f'OBU出入口状态应该是{enterStatus[i]},实际为: {ETC_TradeEntranceStatus}')
            time.sleep(1)
            logging.info(f'OBU 0.5s后切换到出口状态'.center(50, '-'))
            # 设置出口状态
            iStep, _ = Driver['CAN'].SetOBUTradeMoney(Driver, iStep, 0, exitStatus[i])
            time.sleep(0.5)
            # 读取OBU出入口状态
            iStep, ETC_TradeEntranceStatus = Driver['CAN'].getETC_TradeEntranceStatus(iStep)
            with allure.step(f'第{iStep}步:判断OBU出入口状态 # 出入口状态应该是{exitStatus[i]}'):
                with assume: assert ETC_TradeEntranceStatus == exitStatus[i], logging.error(f'OBU出入口状态应该是{exitStatus[i]},实际为: {ETC_TradeEntranceStatus}')
                time.sleep(1)

    @allure.severity('normal')
    @allure.title('5.8G 读取VIN')
    @allure.description('5.8G 读取VIN')
    def test_OBU_VIN(self, action, Driver):
        iStep = 1
        # 检查VIN写入是否成功
        iStep, VIN = Driver['CAN'].getOBUVIN(Driver, iStep)
        with allure.step(f'第{iStep}步:判断VIN写入是否成功 # VIN = {Set_up.testVin}'):
            with assume: assert VIN == Set_up.testVin, logging.error(f'5.8G读取VIN错误,应该是：{Set_up.testVin}，实际: {VIN}')
            iStep += 1


    @allure.severity('normal')
    @allure.title('检查OBU激活状态-已拆卸')
    @allure.description('检查OBU激活状态-已拆卸')
    def test_OBU_ActiveStatus_NOK(self, action, Driver):
        iStep = 1
        # 5.8G 设置OBU防拆位=0
        iStep, _ = Driver['CAN'].setOBUTampersSt(Driver, iStep, 0x00)
        time.sleep(1)
        # 读取OBU激活状态
        iStep, OBU_ActiveStatus = Driver['CAN'].getETC_ActiveStatus(iStep)
        with allure.step(f'第{iStep}步:判断OBU激活状态 # OBU_ActiveStatus = 1'):
            with assume: assert OBU_ActiveStatus == 1, logging.error(f'OBU激活状态应该是1,实际为: {OBU_ActiveStatus}')
            iStep += 1

    @allure.severity('normal')
    @allure.title('检查OBU激活状态-未拆卸')
    @allure.description('检查OBU激活状态-未拆卸')
    def test_OBU_ActiveStatus_OK(self, action, Driver):
        iStep = 1
        # 5.8G 设置OBU防拆位=0
        iStep, _ = Driver['CAN'].setOBUTampersSt(Driver, iStep, 0x01)
        time.sleep(1)
        # 读取OBU激活状态
        iStep, OBU_ActiveStatus = Driver['CAN'].getETC_ActiveStatus(iStep)
        with allure.step(f'第{iStep}步:判断OBU激活状态 # OBU_ActiveStatus = 0'):
            with assume: assert OBU_ActiveStatus == 0, logging.error(f'OBU激活状态应该是0,实际为: {OBU_ActiveStatus}')
            iStep += 1

    @allure.severity('normal')
    @allure.title('检查OBU激活状态切换')
    @allure.description('检查OBU激活状态切换')
    def test_OBU_ActiveStatus_Change(self, action, Driver):
        iStep = 1
        for i in range(6):
            logging.info(f'OBU切换到未激活状态'.center(50, '-'))
            # 5.8G 设置OBU防拆位=0
            iStep, _ = Driver['CAN'].setOBUTampersSt(Driver, iStep, 0x00)
            time.sleep(2)
            # 读取OBU激活状态
            iStep, OBU_ActiveStatus = Driver['CAN'].getETC_ActiveStatus(iStep)
            with allure.step(f'第{iStep}步:判断OBU激活状态 # OBU_ActiveStatus = 1'):
                with assume: assert OBU_ActiveStatus == 1, logging.error(f'OBU激活状态应该是1,实际为: {OBU_ActiveStatus}')
                iStep += 1
            logging.info(f'OBU切换到激活状态'.center(50, '-'))
            # 5.8G 设置OBU防拆位=1
            iStep, _ = Driver['CAN'].setOBUTampersSt(Driver, iStep, 0x01)
            time.sleep(2)
            # 读取OBU激活状态
            iStep, OBU_ActiveStatus = Driver['CAN'].getETC_ActiveStatus(iStep)
            with allure.step(f'第{iStep}步:判断OBU激活状态 # OBU_ActiveStatus = 0'):
                with assume: assert OBU_ActiveStatus == 0, logging.error(f'OBU激活状态应该是0,实际为: {OBU_ActiveStatus}')
                iStep += 1

    @allure.severity('normal')
    @allure.title('测试OBU防拆认证功能-不发送认证码,应认证失败')
    @allure.description('测试OBU防拆认证功能-不发送认证码,应认证失败')
    def test_OBU_AntiDismantleAuthent_NoAuthCode(self, action, Driver):
        iStep = 1
        Set_up.CalcCMAC = False
        # 写入VIN
        Set_up.testVin = [random.randint(0, 255) for _ in range(17)]
        vinString = "2E F1 90" + " ".join(["{:02X}".format(byte) for byte in Set_up.testVin])
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, vinString, "6E F1 90", 3, iStep, True)
        # 断电重启
        iStep= Driver['CAN'].restartETC_Power(Driver, iStep)
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, '22 F1 90', "62 F1 90", 0, iStep, False)
        time.sleep(40)
        # 检查ETC防拆认证结果
        iStep, ETC_AntiDismantleAuthentRes = Driver['CAN'].getETC_AntiDismantleAuthentRes(iStep)
        with allure.step(f'第{iStep}步:判断认证结果 # ETC_AntiDismantleAuthentRes = 0'):
            with assume: assert ETC_AntiDismantleAuthentRes == 1, logging.error(f'OBU防拆状态应该是1,实际为: {ETC_AntiDismantleAuthentRes}')
            iStep += 1

    @allure.severity('normal')
    @allure.title('测试OBU防拆认证功能-认证成功')
    @allure.description('测试OBU防拆认证功能-认证成功')
    def test_OBU_AntiDismantleAuthent(self, action, Driver):
        iStep = 1
        Set_up.CalcCMAC = False
        # 写入VIN
        Set_up.testVin = [random.randint(0, 255) for _ in range(17)]
        vinString = "2E F1 90" + " ".join(["{:02X}".format(byte) for byte in Set_up.testVin])
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, vinString, "6E F1 90", 3, iStep, True)
        # 断电重启
        iStep= Driver['CAN'].restartETC_Power(Driver, iStep)
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, '22 F1 90', "62 F1 90", 0, iStep, False)
        time.sleep(25)
        # 获取OBU发送的随机数
        randNumber = Driver['CAN'].recv_frame_by_id(Driver, 0xBB, 3)
        self.calc_OBU_AuthCode(Driver, iStep, randNumber)
        # 检查ETC防拆认证结果
        iStep, ETC_AntiDismantleAuthentRes = Driver['CAN'].getETC_AntiDismantleAuthentRes(iStep)
        with allure.step(f'第{iStep}步:判断认证结果 # ETC_AntiDismantleAuthentRes = 0'):
            with assume: assert ETC_AntiDismantleAuthentRes == 0, logging.error(f'OBU防拆状态应该是0,实际为: {ETC_AntiDismantleAuthentRes}')
            iStep += 1

    
    @allure.severity('normal')
    @allure.title('测试OBU发出防拆认证随机数次数')
    @allure.description('测试OBU发出防拆认证随机数次数')
    def test_OBU_AntiDismantleAuthent_Num(self, action, Driver):
        iStep = 1
        Set_up.CalcCMAC = False
        # 写入VIN
        writeVIN = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]
        vinString = "2E F1 90" + " ".join(["{:02X}".format(byte) for byte in writeVIN])
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, vinString, "6E F1 90", 3, iStep, True)
        # 断电重启
        iStep= Driver['CAN'].restartETC_Power(Driver, iStep)
        time.sleep(25)
        # 获取OBU发送的随机数
        randNumber = Driver['CAN'].recv_frame_by_id(Driver, 0xBB, 3)
        time.sleep(2)
        # 获取第二次随机数
        randNumber2 = Driver['CAN'].recv_frame_by_id(Driver, 0xBB, 3)
        time.sleep(2)
        # 获取第三次随机数
        randNumber3 = Driver['CAN'].recv_frame_by_id(Driver, 0xBB, 10)
        time.sleep(2)
        # 对比随机数
        with allure.step(f'第{iStep}步:判断第三次随机数 # 获取失败'):
            with assume: assert randNumber3 == [], logging.error(f'OBU第三次随机数应为空!')
            iStep += 1

    @allure.severity('normal')
    @allure.title('测试OBU两次发出防拆认证随机数是否相同')
    @allure.description('测试OBU两次发出防拆认证随机数是否相同')
    def test_OBU_AntiDismantleAuthent_Num_Equal(self, action, Driver):
        iStep = 1
        Set_up.CalcCMAC = False
        # 写入VIN
        writeVIN = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]
        vinString = "2E F1 90" + " ".join(["{:02X}".format(byte) for byte in writeVIN])
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, vinString, "6E F1 90", 3, iStep, True)
        # 断电重启
        iStep= Driver['CAN'].restartETC_Power(Driver, iStep)
        time.sleep(25)
        # 获取OBU发送的随机数
        randNumber = Driver['CAN'].recv_frame_by_id(Driver, 0xBB, 3)
        with allure.step(f'第{iStep}步:判断第一次随机数 # 获取成功'):
            with assume: assert randNumber != [], logging.error(f'OBU第一次随机数获取失败!')
        time.sleep(4)
        # 获取第二次随机数
        randNumber2 = Driver['CAN'].recv_frame_by_id(Driver, 0xBB, 3)
        time.sleep(2)
        with allure.step(f'第{iStep}步:判断第二次随机数 # 获取成功'):
            with assume: assert randNumber2 != [], logging.error(f'OBU第二次随机数获取失败!')
        # 对比随机数
        with allure.step(f'第{iStep}步:对比两次随机数 # 随机数不同'):
            with assume: assert randNumber != randNumber2, logging.error(f'OBU两次随机数应该不一致!')
            iStep += 1

    @allure.severity('normal')
    @allure.title('测试OBU防拆认证成功后修改VIN,重启后仍发送旧的认证码,防拆认证应该失败')
    @allure.description('测试OBU防拆认证成功后修改VIN,重启后仍发送旧的认证码,防拆认证应该失败')
    def test_OBU_AntiDismantleAuthent_VIN_Change_After_Success(self, action, Driver):
        iStep = 1
        Set_up.CalcCMAC = False
        # 写入VIN
        Set_up.testVin = [random.randint(0, 255) for _ in range(17)]
        vinString = "2E F1 90" + " ".join(["{:02X}".format(byte) for byte in Set_up.testVin])
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, vinString, "6E F1 90", 3, iStep, True)
        # 断电重启
        iStep= Driver['CAN'].restartETC_Power(Driver, iStep)
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, '22 F1 90', "62 F1 90", 0, iStep, False)
        time.sleep(25)
        # 获取OBU发送的随机数
        randNumber = Driver['CAN'].recv_frame_by_id(Driver, 0xBB, 3)
        self.calc_OBU_AuthCode(Driver, iStep, randNumber)
        # 检查ETC防拆认证结果
        iStep, ETC_AntiDismantleAuthentRes = Driver['CAN'].getETC_AntiDismantleAuthentRes(iStep)
        with allure.step(f'第{iStep}步:判断认证结果 # ETC_AntiDismantleAuthentRes = 0'):
            with assume: assert ETC_AntiDismantleAuthentRes == 0, logging.error(f'OBU防拆状态应该是0,实际为: {ETC_AntiDismantleAuthentRes}')
            iStep += 1
        # 断电重启
        iStep= Driver['CAN'].restartETC_Power(Driver, iStep)
        # 写入新的VIN
        if Set_up.testVin[16] == 0xFF:
            Set_up.testVin[16] = 0x00
        else:
            Set_up.testVin[16] = Set_up.testVin[16] + 1 
        vinString = "2E F1 90" + " ".join(["{:02X}".format(byte) for byte in Set_up.testVin])
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, vinString, "6E F1 90", 3, iStep, True)
        time.sleep(40)
        # 检查ETC防拆认证结果
        iStep, ETC_AntiDismantleAuthentRes = Driver['CAN'].getETC_AntiDismantleAuthentRes(iStep)
        with allure.step(f'第{iStep}步:判断认证结果 # ETC_AntiDismantleAuthentRes = 0'):
            with assume: assert ETC_AntiDismantleAuthentRes == 1, logging.error(f'OBU防拆状态应该是1,实际为: {ETC_AntiDismantleAuthentRes}')
            iStep += 1

    @allure.severity('normal')
    @allure.title('测试OBU防拆认证功能,发送错误的防拆认证码,应认证失败')
    @allure.description('测试OBU防拆认证功能,发送错误的防拆认证码,应认证失败')
    def test_OBU_AntiDismantleAuthent_Error_AuthCode(self, action, Driver):
        iStep = 1
        Set_up.CalcCMAC = False
        # 写入VIN
        Set_up.testVin = [random.randint(0, 255) for _ in range(17)]
        vinString = "2E F1 90" + " ".join(["{:02X}".format(byte) for byte in Set_up.testVin])
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, vinString, "6E F1 90", 3, iStep, True)
        # 断电重启
        iStep= Driver['CAN'].restartETC_Power(Driver, iStep)
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, '22 F1 90', "62 F1 90", 0, iStep, False)
        time.sleep(25)
        # 获取OBU发送的随机数
        randNumber = Driver['CAN'].recv_frame_by_id(Driver, 0xBB, 3)
        iStep = self.calc_OBU_AuthCode(Driver, iStep, randNumber, False)
        # 检查ETC防拆认证结果
        iStep, ETC_AntiDismantleAuthentRes = Driver['CAN'].getETC_AntiDismantleAuthentRes(iStep)
        with allure.step(f'第{iStep}步:判断认证结果 # ETC_AntiDismantleAuthentRes = 0'):
            with assume: assert ETC_AntiDismantleAuthentRes == 1, logging.error(f'OBU防拆状态应该是1,实际为: {ETC_AntiDismantleAuthentRes}')
            iStep += 1
    
    @allure.severity('normal')
    @allure.title('测试OBU防拆认证功能,使用第二次的随机数进行验证,应验证成功')
    @allure.description('测试OBU防拆认证功能,使用第二次的随机数进行验证,应验证成功')
    def test_OBU_AntiDismantleAuthent_After(self, action, Driver):
        iStep = 1
        Set_up.CalcCMAC = False
        # 写入VIN
        Set_up.testVin = [random.randint(0, 255) for _ in range(17)]
        vinString = "2E F1 90" + " ".join(["{:02X}".format(byte) for byte in Set_up.testVin])
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, vinString, "6E F1 90", 3, iStep, True)
        # 断电重启
        iStep= Driver['CAN'].restartETC_Power(Driver, iStep)
        iStep, uds_resp, size = Driver['CAN'].checkReqResp(Driver, '22 F1 90', "62 F1 90", 0, iStep, False)
        time.sleep(25)
        # 获取OBU发送的随机数
        randNumber = Driver['CAN'].recv_frame_by_id(Driver, 0xBB, 3)
        time.sleep(1)
        randNumber = Driver['CAN'].recv_frame_by_id(Driver, 0xBB, 5)
        iStep = self.calc_OBU_AuthCode(Driver, iStep, randNumber)
        # 检查ETC防拆认证结果
        iStep, ETC_AntiDismantleAuthentRes = Driver['CAN'].getETC_AntiDismantleAuthentRes(iStep)
        with allure.step(f'第{iStep}步:判断认证结果 # ETC_AntiDismantleAuthentRes = 0'):
            with assume: assert ETC_AntiDismantleAuthentRes == 0, logging.error(f'OBU防拆状态应该是0,实际为: {ETC_AntiDismantleAuthentRes}')
            iStep += 1


    '''根据随机数计算OBU防拆认证码并发送'''
    def calc_OBU_AuthCode(self, Driver, iStep, randNumber, isTrue = True):
        vinKey = Set_up.testVin[0:8] + Set_up.testVin[-8:]
        with allure.step(f'第{iStep}步:根据随机数计算OBU防拆认证码并发送 # NA'):
            aes_bytes = list(AESCMAC.calculate(randNumber, vinKey))[0:8]
        if isTrue:
            vinAes = aes_bytes
        else:
            if aes_bytes[0] == 0xFF:
                vinAes = [0xFE] + aes_bytes[1:8]
            else:
                vinAes = [aes_bytes[0] + 1] + aes_bytes[1:8]
        Driver['CAN'].TransmitData(0xBA, vinAes, 'CANFD', True)
        iStep += 1
        time.sleep(1)
        return iStep



